package cn.phub.basic.service.impl;

import cn.phub.basic.annotation.PreAuthorize;
import cn.phub.basic.service.IPermissionScanService;
import cn.phub.basic.util.Classutil;
import cn.phub.system.domain.Permission;
import cn.phub.system.mapper.PermissionMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.FileFilter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

@Service
public class PermissionScanServiceImpl implements IPermissionScanService {
    @Autowired
    private PermissionMapper permissionMapper;

    //扫描包的前缀和后缀
    private static final String  PKG_PREFIX   = "cn.phub.";
    private static final String  PKG_SUFFIX   = ".controller";
    @Override
    public void scan() {
        //扫描自定义注解
          // 找到所有的controller
          // 找到controller中的所有方法
          // 遍历方法找到方法上有 @PreAuthorize 注解的
        //获取自定义注解的属性name value 加权限
        String path = this.getClass().getResource("/").getPath() + "/cn/phub/";
        //创建成一个文件,通过文件里面的流来读取里面的内容
        File file = new File(path);
        //files 指的是phub下的所有包 basic org user system 包
        File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.isDirectory();
            }
        });

        //获取org.yaosang.*.web.controller里面所有的类
        //经过for循环 将basic org user system包里的所有controller的所有class文件装到clazzes里面
        Set<Class> clazzes = new HashSet<>();//自动去重
        for (File fileTmp : files) {//遍历basic org user system
            System.out.println(fileTmp.getName());
            // cn.phub.org.controller
            clazzes.addAll(Classutil.getClasses(PKG_PREFIX+fileTmp.getName()+PKG_SUFFIX));
        }

        //遍历所有的controller
        for (Class clazz : clazzes) {
            //找到当前类中的所有方法,每一次遍历拿到一个类
            Method[] methods = clazz.getMethods();
            if (methods==null || methods.length<1)
                return;//为空 返回空
            for (Method method : methods) {
                try {                       //校验方法上有没有想要的注解
                    PreAuthorize preAuthorizeAnno = method.getAnnotation(PreAuthorize.class);
                    if (preAuthorizeAnno==null)
                        continue;
                    //拿到name和value了
                    String name = preAuthorizeAnno.name();
                    String permissionSn = preAuthorizeAnno.value();
                    //得到当前方法的URI
                    String uri = getUri(clazz, method);
                    //通过sn查询有没有
                    Permission permissionTmp = permissionMapper.loadBySn(permissionSn);
                    //如果不存在就添加
                    if (permissionTmp == null) {
                        Permission permission = new Permission();
                        permission.setName(name);
                        permission.setSn(permissionSn);
                        permission.setUrl(uri);
                        permissionMapper.save(permission);
                    }else{
                        //如果存在就修改
                        permissionTmp.setName(name);
                        permissionTmp.setSn(permissionSn);
                        permissionTmp.setUrl(uri);
                        permissionMapper.update(permissionTmp);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 获取请求的URI
     * @param clazz
     * @param method
     * @return
     */
    //给一个类的字节码和方法进来，拿到方法的访问路径返回给你
    //拼接相关方法方法的路径,拿到了上面直接调用
    private String getUri(Class clazz, Method method) {
        String classPath = "";
        Annotation annotation = clazz.getAnnotation(RequestMapping.class);
        if (annotation!=null){
            RequestMapping requestMapping = (RequestMapping) annotation;
            String[] values = requestMapping.value();
            if(values!=null&&values.length>0){
                classPath = values[0];
                if (!"".equals(classPath)&&!classPath.startsWith("/"))
                    classPath="/"+classPath;
            }
        }
        GetMapping getMapping =  method.getAnnotation(GetMapping.class);
        String methodPath = "";
        if (getMapping!=null){
            String[] values = getMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        PostMapping postMapping =  method.getAnnotation(PostMapping.class);
        if (postMapping!=null){
            String[] values = postMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        DeleteMapping deleteMapping =  method.getAnnotation(DeleteMapping.class);
        if (deleteMapping!=null){
            String[] values = deleteMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        PutMapping putMapping =  method.getAnnotation(PutMapping.class);
        if (putMapping!=null){
            String[] values = putMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }

        }
        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
        if (patchMapping!=null){
            String[] values = patchMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        if (requestMapping!=null){
            String[] values = requestMapping.value();
            if(values!=null&&values.length>0){
                methodPath = values[0];
                if (!"".equals(methodPath)&&!methodPath.startsWith("/"))
                    methodPath="/"+methodPath;
            }
        }
        return classPath+methodPath;
    }
}
